﻿using System;
using Castle.MicroKernel;
using Castle.MicroKernel.Context;
using Castle.MicroKernel.Proxy;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.Resolvers;
using Castle.Windsor;
using Castle.Windsor.Installer;
using FamilyBook.Core;
using FamilyBook.Core.Services;

namespace FamilyBook.Infrastructure
{
    public class ServiceFactory : IDisposable
    {
        private static IWindsorContainer _iocContainer;

        private class ArgumentPassingDependencyResolver : DefaultDependencyResolver
        {
            protected override CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
            {
                if (parameterType.ContainsGenericParameters)
                {
                    // this behaviour copied from base class
                    return current;
                }

                // the difference in the following line is that "true" is passed
                // instead of "false" as the third parameter
                return new CreationContext(parameterType, current, true);
            }
        }

        public ServiceFactory()
        {
            if (_iocContainer != null)
                return;

            IKernel defKernel = new DefaultKernel(new ArgumentPassingDependencyResolver(), new NotSupportedProxyFactory());
            _iocContainer = new WindsorContainer(defKernel, new DefaultComponentInstaller()).Install(Configuration.FromAppConfig());

            //_iocContainer.Register(Component.For<IConfiguration>().ImplementedBy<AppConfig>());
            //_iocContainer.Register(Component.For(typeof(IGeneralRepository<,>)).ImplementedBy(typeof(GeneralRepository<,>)));
            _iocContainer.Register(Component.For(typeof(GeneralService<,>)).LifestyleTransient());
            _iocContainer.Register(Component.For<SequenceService>().LifestyleTransient());
            _iocContainer.Register(Component.For(typeof(AccountService<>)).LifestyleTransient());
            _iocContainer.Register(Component.For<CounterpartyService>().LifestyleTransient());
            _iocContainer.Register(Component.For<UserService>().LifestyleTransient());
        }

        public TEntity Create<TEntity>(IDbSession dbSession = null) where TEntity : class
        {
            return _iocContainer.Resolve<TEntity>(new { dbSession });
        }

        public void Release(object instance)
        {
            _iocContainer.Release(instance);
        }

        public void Dispose()
        {
            if (_iocContainer != null)
            {
                _iocContainer.Dispose();
                _iocContainer = null;
            }
        }
    }
}
